<template>
  <view class="nut-elevator">
    <scroll-view
      class="nut-elevator__list scrollview"
      :scroll-top="scrollTop"
      :scroll-y="true"
      :scroll-with-animation="true"
      :scroll-anchoring="true"
      ref="listview"
      :style="{ height: isNaN(+height) ? height : `${height}px` }"
      @scroll="listViewScroll"
    >
      <view :class="['nut-elevator__list__item', `elevator__item__${0}`]">
        <view class="nut-elevator__list__item__code">当前选择</view>
        <view class="area-name nut-elevator__list__item__name current_item_name">{{ city }}</view>
      </view>
      <view :class="['nut-elevator__list__item', `elevator__item__${index + 1}`]" v-for="(item, index) in indexList" :key="item[acceptKey]" :ref="setListGroup">
        <view class="nut-elevator__list__item__code">{{ item[acceptKey] }}</view>
        <view
          class="nut-elevator__list__item__name"
          :class="{
            'nut-elevator__list__item__name--highcolor': currentData.id === subitem.id && currentKey === item[acceptKey]
          }"
          v-for="subitem in item.list"
          :key="subitem['id']"
          @click="handleClickItem(item[acceptKey], subitem)"
          v-html="subitem.name"
        ></view>
      </view>
      <view class="nut-elevator__list__fixed" :style="fixedStyle" v-show="scrollY > 0" v-if="isSticky">
        <span class="fixed-title">{{ indexList[currentIndex][acceptKey] }}</span>
      </view>
    </scroll-view>
    <view class="nut-elevator__code--current" v-show="scrollStart" v-if="indexList.length > 0">
      {{ indexList[codeIndex][acceptKey] }}
    </view>
    <view class="nut-elevator__bars" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd">
      <view class="nut-elevator__bars__inner">
        <view
          class="nut-elevator__bars__inner__item"
          :class="{ active: item[acceptKey] === indexList[currentIndex] && indexList[currentIndex][acceptKey] }"
          :data-index="index"
          v-for="(item, index) in indexList"
          :key="item[acceptKey]"
          @click="handleClickIndex(item[acceptKey])"
          >{{ item[acceptKey] }}</view
        >
      </view>
    </view>
  </view>
</template>
<script lang="ts" setup>
import { computed, nextTick, ref, watch, defineEmits, defineProps } from 'vue'
import Taro from '@tarojs/taro'

interface ElevatorData {
  name: string
  id: number | string
  [key: string]: string | number
}

const props = defineProps({
  height: {
    type: [Number, String],
    default: '200px'
  },
  acceptKey: {
    type: [String],
    default: 'title'
  },
  indexList: {
    type: Array,
    default: () => {
      return []
    }
  },
  isSticky: {
    type: [Boolean],
    default: false
  },
  spaceHeight: {
    type: [Number],
    default: 23
  },
  titleHeight: {
    type: [Number],
    default: 35
  }
})

const city = ref(' ')

const emit = defineEmits(['click-item', 'click-index'])

const spaceHeight = ref(23)
const listview: any = ref()
const anchorIndex = ref(0)
const codeIndex = ref(0)
const listHeight: any = ref([])
const listGroup: any = ref([])
const touchState = ref({ y1: 0, y2: 0 })
const scrollStart = ref(false)
const currentIndex = ref(0)
const query = Taro.createSelectorQuery()
const scrollTop = ref(0)
const currentData = ref({})
const currentKey = ref('')
const scrollY = ref(0)
const diff = ref(-1)
const fixedTop = ref(0)

const fixedStyle = computed(() => {
  return {
    transform: `translate3d(0, ${scrollY.value + fixedTop.value}px, 0)`
  }
})

const clientHeight = computed(() => {
  return listview.value.clientHeight
})

const getData = el => {
  if (!el.dataset.index) {
    return '0'
  }
  return el.dataset.index as string
}

const setListGroup = el => {
  nextTick(() => {
    if (!listGroup.value.includes(el) && el != null) {
      listGroup.value.push(el)
    }
  })
}
const calculateHeight = () => {
  const cityData = Taro.getStorageSync('city')
  if (cityData) city.value = cityData.name

  listHeight.value = []
  let height = 0
  listHeight.value.push(height)
  for (let i = 0; i < listGroup.value.length; i++) {
    query.selectAll(`.elevator__item__${i}`).boundingClientRect()
    query.exec((res: any) => {
      height += res[i][0].height
      listHeight.value.push(height)
    })
  }
}

const scrollTo = (index: number) => {
  if (!index && index !== 0) {
    return
  }
  if (index < 0) index = 0
  if (index > listHeight.value.length - 2) index = listHeight.value.length - 2
  codeIndex.value = index
  scrollTop.value = listHeight.value[index + 1]
}

const touchStart = e => {
  scrollStart.value = true
  let index = getData(e.target)
  let firstTouch = e.touches[0]
  touchState.value.y1 = firstTouch.pageY
  anchorIndex.value = +index
  codeIndex.value = +index
  scrollTo(+index)
}

const touchMove = (e: TouchEvent) => {
  let firstTouch = e.touches[0]
  touchState.value.y2 = firstTouch.pageY
  let delta = ((touchState.value.y2 - touchState.value.y1) / spaceHeight.value) | 0
  codeIndex.value = anchorIndex.value + delta
  scrollTo(codeIndex.value)
}

const touchEnd = () => {
  scrollStart.value = false
}

const handleClickItem = (key: string, item: ElevatorData) => {
  emit('click-item', key, item)
  Taro.setStorage({
    key: 'city',
    data: item
  })
  currentData.value = item
  currentKey.value = key
  Taro.navigateBack()
}

const handleClickIndex = (key: string) => {
  emit('click-index', key)
}

const listViewScroll = (e: Event) => {
  let target = e.target as Element
  let scrollTop = target.scrollTop
  const _listHeight = listHeight.value
  scrollY.value = Math.floor(scrollTop)
  for (let i = 0; i < _listHeight.length - 1; i++) {
    let height1 = _listHeight[i]
    let height2 = _listHeight[i + 1]
    if (scrollY >= height1 && scrollY.value < height2) {
      currentIndex.value = i
      diff.value = height2 - scrollY.value
      return
    }
  }

  currentIndex.value = _listHeight.length - 2
}

watch(
  () => listGroup.value.length,
  () => {
    Taro.nextTick(calculateHeight)
  }
)

watch(
  () => diff.value,
  (newVal: number) => {
    const _listHeight = listHeight.value
    let _fixedTop = newVal > 0 && newVal < props.titleHeight ? newVal - props.titleHeight : 0
    if (scrollY.value + clientHeight.value === _listHeight[_listHeight.length - 1]) {
      if (_listHeight !== 0) _fixedTop = 0
    }
    if (fixedTop.value === _fixedTop) return
    fixedTop.value = _fixedTop
  }
)
</script>

<style lang="scss">
.current_item_name {
  color: #fa2c19;
}
</style>
